package com.mxz.auth.service;

import com.mxz.auth.form.LoginBody;
import com.mxz.auth.form.RegisterBody;
import com.mxz.common.core.constant.Constants;
import com.mxz.common.core.constant.UserConstants;
import com.mxz.common.core.enums.UserStatus;
import com.mxz.common.core.utils.ServletUtils;
import com.mxz.common.core.utils.StringUtils;
import com.mxz.common.core.utils.ip.IpUtils;
import com.mxz.common.core.web.domain.AjaxResult;
import com.mxz.common.security.service.TokenService;
import com.mxz.common.security.utils.SecurityUtils;
import com.mxz.system.domain.SysLogininfor;
import com.mxz.common.api.domain.SysUser;
import com.mxz.common.api.model.LoginUser;
import com.mxz.system.service.SysConfigService;
import com.mxz.system.service.SysLogininforService;
import com.mxz.system.service.SysPermissionService;
import com.mxz.system.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Set;

/**
 * 登录校验方法
 *
 * @author mxz
 */
@Component
public class SysLoginService {

    @Autowired
    private SysUserService userService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private SysConfigService configService;

    @Autowired
    private SysLogininforService logininforService;

    @Autowired
    private TokenService tokenService;

    /**
     * 登录
     */
    public AjaxResult login(LoginBody form) {
        String userName = form.getUsername();
        String password = form.getPassword();
        // 用户名或密码为空 错误
        if (StringUtils.isAnyBlank(userName, password)) {
            recordLogininfor(userName, Constants.LOGIN_FAIL, "用户/密码必须填写");
            return AjaxResult.error("用户/密码必须填写");
        }
        // 密码如果不在指定范围内 错误
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
            recordLogininfor(userName, Constants.LOGIN_FAIL, "用户密码不在指定范围");
            return AjaxResult.error("用户密码不在指定范围");
        }
        // 用户名不在指定范围内 错误
        if (userName.length() < UserConstants.USERNAME_MIN_LENGTH
                || userName.length() > UserConstants.USERNAME_MAX_LENGTH) {
            recordLogininfor(userName, Constants.LOGIN_FAIL, "用户名不在指定范围");
            return AjaxResult.error("用户名不在指定范围");
        }
        // 查询用户信息
        SysUser sysUser = userService.selectUserByUserName(userName);
        if (StringUtils.isNull(sysUser)) {
            recordLogininfor(userName, Constants.LOGIN_FAIL, "登录用户不存在");
            return AjaxResult.error("登录用户不存在");
        }
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(sysUser.getUserId());
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(sysUser.getUserId());
        LoginUser userInfo = new LoginUser();
        userInfo.setSysUser(sysUser);
        userInfo.setRoles(roles);
        userInfo.setPermissions(permissions);

        SysUser user = userInfo.getSysUser();
        if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
            recordLogininfor(userName, Constants.LOGIN_FAIL, "对不起，您的账号已被删除");
            return AjaxResult.error("对不起，您的账号已被删除");
        }
        if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            recordLogininfor(userName, Constants.LOGIN_FAIL, "用户已停用，请联系管理员");
            return AjaxResult.error("用户已停用，请联系管理员");
        }
        if (!SecurityUtils.matchesPassword(password, user.getPassword())) {
            recordLogininfor(userName, Constants.LOGIN_FAIL, "用户密码错误");
            return AjaxResult.error("用户密码错误");
        }
        recordLogininfor(userName, Constants.LOGIN_SUCCESS, "登录成功");
        // 获取登录token
        return AjaxResult.success("登录成功", tokenService.createToken(userInfo));
    }

    /**
     * 退出
     */
    public void logout(String loginName) {
        recordLogininfor(loginName, Constants.LOGOUT, "退出成功");
    }

    /**
     * 注册
     */
    public AjaxResult register(RegisterBody registerBody) {
        String userName = registerBody.getUsername();
        String password = registerBody.getPassword();
        // 用户名或密码为空 错误
        if (StringUtils.isAnyBlank(userName, password)) {
            return AjaxResult.error("用户/密码必须填写");
        }
        if (userName.length() < UserConstants.USERNAME_MIN_LENGTH
                || userName.length() > UserConstants.USERNAME_MAX_LENGTH) {
            return AjaxResult.error("账户长度必须在2到20个字符之间");
        }
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
            return AjaxResult.error("密码长度必须在5到20个字符之间");
        }

        // 注册用户信息
        SysUser sysUser = new SysUser();
        sysUser.setUserName(userName);
        sysUser.setNickName(userName);
        sysUser.setPassword(SecurityUtils.encryptPassword(password));

        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
            return AjaxResult.error("当前系统没有开启注册功能！");
        }
        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(userName))) {
            return AjaxResult.error("保存用户'" + userName + "'失败，注册账号已存在");
        }
        userService.registerUser(sysUser);

        recordLogininfor(userName, Constants.REGISTER, "注册成功");
        return AjaxResult.success("注册成功");
    }

    /**
     * 【私有公共方法】记录登录信息
     *
     * @param username 用户名
     * @param status   状态
     * @param message  消息内容
     * @return
     */
    private void recordLogininfor(String username, String status, String message) {
        SysLogininfor logininfor = new SysLogininfor();
        logininfor.setUserName(username);
        logininfor.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
        logininfor.setMsg(message);
        // 日志状态
        if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
            logininfor.setStatus("0");
        } else if (Constants.LOGIN_FAIL.equals(status)) {
            logininfor.setStatus("1");
        }
        logininforService.insertLogininfor(logininfor);
    }
}